单例bean依赖原型bean的 如何保证原型bean生命周期 您所在的位置:网站首页 javabean有四个scope 生命周期 单例bean依赖原型bean的 如何保证原型bean生命周期

单例bean依赖原型bean的 如何保证原型bean生命周期

2023-03-26 07:16| 来源: 网络整理| 查看: 265

简介:

将原型bean注入到单例bean,会破坏原型bean的生命周期,使其的生命周期变成与单例bean相同。

情况模拟: 1、单例bean @Component public class SingletonBean { @Autowired private PrototypeBean prototypeBean; public void printTime() { System.out.println("SingletonBean: "+this.hashCode()); System.out.println("prototypeBean 注入给单例的:"+prototypeBean.hashCode()); prototypeBean.printTime(); } } 2、原型bean @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class PrototypeBean { Long timeMilis; public PrototypeBean() { //System.out.println("PrototypeBean Constructor"); this.timeMilis = System.currentTimeMillis(); } public void printTime() { System.out.println("PrototypeBean原始bean:"+this.hashCode()); System.out.println("timeMils:" + timeMilis); } } 3、测试类 public class PrototypeTest { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(PrototypeBeanConfig.class); SingletonBean singletonBean = (SingletonBean) applicationContext.getBean("singletonBean"); SingletonBean singletonBean1 = (SingletonBean) applicationContext.getBean("singletonBean"); SingletonBean singletonBean2 = (SingletonBean) applicationContext.getBean("singletonBean"); singletonBean.printTime(); singletonBean1.printTime(); singletonBean2.printTime(); } } 4、测试结果

 

 

5、原因分析:

要知道, SingletonBean 是单例模式的,只会被Spring进行类扫面的时候创建一次,然后存入到单例池SingletonObjects。之后每次使用SingletonBean,都会从单例池中获取,不会再次创建。因为属性的注入发生在创建bean的过程中,所以也只会在创建的时候注入一次。也就是说,在SingletonBean创建过程中,将生成一个PrototypeBean类的bean作为属性注入到SingletonBean中。而以后使用SingletonBean 的 prototypeBean 属性时不会重新生成

PrototypeBean类的bean,只会使用已经注入到SingletonBean属性上的bean。因此PrototypeBean失去了原型bean的生命周期。

解决方式: 一、单例bean实现ApplicationContextAware接口

单例bean不让spring进行属性原型bean的属性注入。而是每次使用的时候,通过getBean的方式获取原型bean。

1、单例bean @Component public class SingletonBeanImplementApplicationContextAware implements ApplicationContextAware { ApplicationContext applicationContext; private PrototypeBean prototypeBean; public void printTime() { System.out.println("SingletonBean: " + this.hashCode()); prototypeBean= (PrototypeBean) applicationContext.getBean("prototypeBean"); System.out.println("prototypeBean 注入给单例的:"+ prototypeBean.hashCode()); prototypeBean.printTime(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext=applicationContext; } } 2、原型bean @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class PrototypeBean { Long timeMilis; public PrototypeBean() { //System.out.println("PrototypeBean Constructor"); this.timeMilis = System.currentTimeMillis(); } public void printTime() { System.out.println("PrototypeBean原始bean:"+this.hashCode()); System.out.println("timeMils:" + timeMilis); } } 3、测试类 public class PrototypeTest { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(PrototypeBeanConfig.class); SingletonBeanImplementApplicationContextAware singletonBean = (SingletonBeanImplementApplicationContextAware) applicationContext.getBean("singletonBeanImplementApplicationContextAware"); SingletonBeanImplementApplicationContextAware singletonBean1 = (SingletonBeanImplementApplicationContextAware) applicationContext.getBean("singletonBeanImplementApplicationContextAware"); SingletonBeanImplementApplicationContextAware singletonBean2 = (SingletonBeanImplementApplicationContextAware) applicationContext.getBean("singletonBeanImplementApplicationContextAware"); singletonBean.printTime(); singletonBean1.printTime(); singletonBean2.printTime(); } } 4、测试结果:

 

 

5、原因分析:

  让单例bean实现ApplicationContextAware接口,重写setApplicationContext方法,获取到ApplicationContex,每次使用 prototypeBean的时候,都从ApplicationContext中通过getBean的方式来获取最新的原型bean,每次获取的原型bean都是Spring新创建的bean。因此可以保证原型bean的生命周期。

二、@Lookup

通过加有@Lookup的抽象方法来获取prototypeBean对象。

1、单例bean @Component public abstract class SingletonBeanByLookup { private PrototypeBean prototypeBean; @Lookup public abstract PrototypeBean getPrototypeBean(); public void printTime() { System.out.println(this.hashCode()); prototypeBean= getPrototypeBean() ; System.out.println(prototypeBean.hashCode()); prototypeBean.printTime(); } } 2、原型bean @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class PrototypeBean { Long timeMilis; public PrototypeBean() { //System.out.println("PrototypeBean Constructor"); this.timeMilis = System.currentTimeMillis(); } public void printTime() { System.out.println("PrototypeBean原始bean:"+this.hashCode()); System.out.println("timeMils:" + timeMilis); } } 3、测试类 public class PrototypeTest { public static void main(String[] args) throws InterruptedException { AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(PrototypeBeanConfig.class); SingletonBeanByLookup singletonBean = (SingletonBeanByLookup) applicationContext.getBean("singletonBeanByLookup"); SingletonBeanByLookup singletonBean1 = (SingletonBeanByLookup) applicationContext.getBean("singletonBeanByLookup"); SingletonBeanByLookup singletonBean2 = (SingletonBeanByLookup) applicationContext.getBean("singletonBeanByLookup"); singletonBean.printTime(); Thread.sleep(1000); singletonBean1.printTime(); Thread.sleep(1000); singletonBean2.printTime(); } } 4、测试结果

 

 

5、原因分析:

系统会生成SingletonBeanByLookup的代理对象作为 SingletonBeanByLookup对象的bean,系统的代理对象是应用了Srping应用了CGLIB(动态代理)类库。Spring在初始化容器的时候对配置@lookup的bean做了特殊处理,Spring会对bean指定的class做动态代理,代理@lookup标签中name属性所指定的方法,返回bean属性指定的bean实例对象。每次我们调用@lookup方法时,其实是调用了CGLIB生成的动态代理类的方法。就是进入org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], org.springframework.cglib.proxy.MethodProxy) 方法中在此拦截器方法中 通过getBean 获取对应的bean。

  三、原型bean使用代理模式

  在原型bean的@Scope 标签中 添加“proxyMode = ScopedProxyMode.TARGET_CLASS”,如:  @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = ScopedProxyMode.TARGET_CLASS)

1、单例bean @Component public class SingletonBean { @Autowired private PrototypeBean prototypeBean; public void printTime() { System.out.println("SingletonBean: "+this.hashCode()); System.out.println("prototypeBean 注入给单例的:"+prototypeBean.hashCode()); prototypeBean.printTime(); } } 2、原型bean @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = ScopedProxyMode.TARGET_CLASS) public class PrototypeBean { Long timeMilis; public PrototypeBean() { //System.out.println("PrototypeBean Constructor"); this.timeMilis = System.currentTimeMillis(); } public void printTime() { System.out.println("PrototypeBean原始bean:"+this.hashCode()); System.out.println("timeMils:" + timeMilis); } } 3、测试类 public class PrototypeTest { public static void main(String[] args) throws InterruptedException { AnnotationConfigApplicationContext applicationContext= new AnnotationConfigApplicationContext(PrototypeBeanConfig.class); SingletonBean singletonBean = (SingletonBean) applicationContext.getBean("singletonBean"); SingletonBean singletonBean1 = (SingletonBean) applicationContext.getBean("singletonBean"); SingletonBean singletonBean2 = (SingletonBean) applicationContext.getBean("singletonBean"); singletonBean.printTime(); Thread.sleep(1000); singletonBean1.printTime(); Thread.sleep(1000); singletonBean2.printTime(); } } 4、测试结果:

 

 

5、原因分析:

这种方法将prototypeBean类生成一个代理对象赋值给singletonBean,每次调用代理方法的时候,会通过getBean去获取一个原始的PrototypeBean。** This will lead to the creation of a proxy. That proxy is created once and will be* returned for each call to getBean. As soon as you invoke a method on the proxy it will,* based on the scope, either create a new one or reuse an existing one.* As you have specified the scope as prototype each method invocation will lead to a new object.



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有